#include "../include/log.h"

//对应级别类型的宏定义数字位置，定义为相应名称的字符串
const char* log_level_str[] = {
    //系统不可用
    [LOG_EMERG] = "EMERG",  
    //必须马上采取行动的事件
    [LOG_ALERT] = "ALERT",  
    //关键的事件
    [LOG_CRIT] = "CRIT",
    //错误事件
    [LOG_ERR] = "ERR",
    //警告事件
    [LOG_WARNING] = "WARNING",
    //普通但重要的事件
    [LOG_NOTICE] = "NOTICE",
    //有用的信息
    [LOG_INFO] = "INFO",
    //调试信息
    [LOG_DEBUG] = "DEBUG",
};

//获取当前时间
void get_current_time(char* buff, int len)
{
    time_t t;
    struct tm* timeinfo;

    time(&t);
    timeinfo = gmtime(&t);

    //将len - 1个字节输入buff
    snprintf(buff, len - 1,"%d/%d/%d %d:%d:%d",
             timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
             timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
}

//va_list是在C语言中解决变参问题的一组宏
//变参问题是指参数的个数不定
//可以是传入一个参数也可以是多个
//可变参数中的每个参数的类型可以不同,也可以相同
//可变参数的每个参数并没有实际的名称与之相对应
void vlog_message(int level, char* clientName, char* fmt, va_list args)
{
    char buff[MAX_LOG_LEN + 1] = {0};
    char time[128] = {0};

    get_current_time(time, sizeof(time));
    vsnprintf(buff, sizeof(buff), fmt, args);

    //在标准输出上打印一次
    printf("%s %s[%s][%d][%ld]%s\n",
            time, clientName, log_level_str[level],getpid(),pthread_self(), buff);
    char pathName[256] = {0};
    sprintf(pathName, "/home/%s/usrLog.log", clientName);

    FILE* fp = fopen(pathName, "a");
    
    //组装需要的信息  时间，级别，进程号，线程号,日志内容记录到自己的日志
    fprintf(fp, "%s %s[%s][%d][%ld]%s\n", 
            time, clientName, log_level_str[level],getpid(),pthread_self(), buff);

    fclose(fp);

    //记录到 系统日志 在 cat/var/log/syslog 可查看日志
    syslog(level, "%s", buff);
}

//C 库宏 void va_start(va_list ap, last_arg) 初始化 ap 变量
//它与 va_arg 和 va_end 宏是一起使用的
//last_arg 是最后一个传递给函数的已知的固定参数
//即省略号之前的参数
//void log_message(int level, char* fmt, ...)
//{
//    va_list args;
//    va_start(args, fmt);
//    vlog_message(level, fmt, args);
//    va_end(args);
//}

//进程池，客户名，设置最高可记录日志信息的等级，当前记录日志的等级, 消息...
void mylog(pthreadpool_t pthreadpool,char *clientName, int maxLevel, int myLevel,char* fmt, ...)
{
    //写日志前，加锁，只能一个客户端进行原子操作
    pthread_mutex_lock(&pthreadpool.mutex);
    //打开一个到系统日志记录程序的连接
    openlog(clientName, LOG_PID, 0);

    //设置记录日志的优先级，则系统日志就只记录指定优先级及以下的日志消息
    setlogmask(LOG_UPTO(maxLevel));

    va_list args;
    va_start(args, fmt);
    vlog_message(myLevel, clientName, fmt, args);
    va_end(args);

    //关闭写日志 + 解锁
    closelog();
    pthread_mutex_unlock(&pthreadpool.mutex);
}
